{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 数值计算基础 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "桂龙成\n",
    "18684752903\n",
    "guilongcheng@hunnu.edu.cn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "参考教材：\n",
    "* 刘金远等，2012，计算物理学，科学出版社\n",
    "* 刘川，计算物理\n",
    "* T.Pang, 2006, An Introduction to Computational Physics, Cambridge University Press\n",
    "\n",
    "https://gitee.com/gui-longcheng/computational-physics-jupyter.git"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 计算物理学对解决复杂物理问题的巨大能力，使它成为物理学的第三支柱，并在物理学研究中占有重要的位置。\n",
    "* 实验、理论、计算\n",
    "* 各个物理学分支都会有计算物理的应用：\n",
    "  * 粒子物理\n",
    "  * 天体物理、宇宙学\n",
    "  * 凝聚态物理、光学\n",
    "  * ..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  1.1 计算机硬件基础"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 计算离不开计算机，应该了解一些计算的硬件基础。\n",
    "* 远古的计算设备--算盘\n",
    "* 现代的计算机架构--冯诺依曼计算机：运算器+控制器+存储器+输入设备+输出设备\n",
    "![von Neumann](./pic/sec1-computer2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 存储器：硬盘(10ms;$ 100\\mu s $)-内存(100ns)-缓存(10ns,3ns,1ns)-寄存器(0.5ns)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 运算器: 算术逻辑运算单元（ALU）,浮点运算单元(FPU),寄存器组\n",
    "* 以两个数的加法为例 $$ 5 + 7 $$ \n",
    "* 全加器：每位全加器由两个半加器构成。每个半加器由一个异或门和与门构成。\n",
    "![逻辑门](./pic/sec1-3-computer3.png)\n",
    "![半加器](./pic/sec1-3-computer4.png)\n",
    "![半加器](./pic/sec1-3-computer5.png)\n",
    "![半加器](./pic/sec1-3-computer6.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 控制器：控制单元(CU),命令存储器(IR),地址寄存器(MAR),节拍发生器，计数器(PC)，指令译码器等。\n",
    "* 指令 操作码 地址码 add reg1 reg2\n",
    "* 取指令->CU分析指令->运行指令->输出设备或保存结果\n",
    "* 所有的程序最终都会变成二进制的机器码。比如一个c语言文件，经过预处理-编译-汇编-链接 生成的可执行程序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "a = np.array([5,7,-7],\">i1\")\n",
    "a.tobytes()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 数的计算机表示"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 有限的内存，只能表达有限多的数。\n",
    "* 二进制表示，一般用4个字节(byte)表示整数（32位)。非负整数 $$ n=\\sum_{i=0}^{31}b_{i}2^{i} $$ 表示范围$ 0\\sim 2^{32}-1 $。\n",
    "* 有符号整数，最高位为符号位，故表示范围 $ -2^{31} \\sim 2^{31} - 1 $。在计算机中一般用补码形式来表示整数（方便减法运算）。\n",
    "* 整数的特点：只要在其定义域之内，机器对于整数的表达是严格的。而且整数之间的运算也是严格的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 实数，一般采用浮点数来表示。\n",
    "* 实数构成不可数多的连续统，因此无法用有限多的机器位来全部表示。\n",
    "* 浮点数系统保证了在任何一个实数的足够接近的邻域内总能找到一个浮点数来近似代表相应的实数。\n",
    "* 不能用有限位来表示的实数其实是取了近似，从而引入了误差，称为舍入误差。\n",
    "* 定义一个在机器上能够表达的最小的正实数，被称为机器精度： $$ \\epsilon_{M}=\\min\\{g\\in A\\mid1\\oplus g>1,g>0\\} $$ A表示计算机中所有可以表示的实数，$ \\oplus $表示计算机中实现的“加法”(里面包含了对结果的舍入)。\n",
    "* 机器精度的数值依赖于我们在一个实数上愿意投入多少内存。通常单精度的实数(4个字节)$ \\epsilon_{M}\\sim10^{-7} $.双精度实数$ \\epsilon_{M}\\sim10^{-16} $。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "epsilon = 1\n",
    "while 1 + epsilon != 1:\n",
    "    epsilon_2=epsilon\n",
    "    epsilon /= 2\n",
    "print(epsilon_2,2**(-52),2**(-23))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 对于浮点数系统，如果选取一个正的自然数 $ \\beta\\in\\mathcal{N} $ 为底来表达的话（如 $\\beta=2$ ），那么一般实数 $x$ 在以 $\\beta$ 为底的系统中可以用下列整数部分和小数部分分别具有 $(n+1)$ 位和 $m$ 位的小数表达 $$x_{\\beta}=(-)^{s}\\left[x_{n}x_{n-1}\\cdots x_{1}x_{0}\\cdot x_{-1}x_{-2}\\cdots x_{-m}\\right],\\quad x_{n}\\neq0$$ 其中 $s=0,1$ 称为符号位。这个表示称为实数 $x$ (以 $\\beta$ 为底)的位置表示。另一种等价的写法 $$x_{\\beta}=(-)^{s}\\left[\\sum_{k=-m}^{n}x_{k}\\beta^{k}.\\right]$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 更为经济与方便的计数方法是将实数提出一个公共的因子， $$x_{\\beta}=(-1)^{s}\\cdot\\left(0.a_{1}a_{2}\\cdots a_{t}\\right)\\cdot\\beta^{e}=(-1)^{s}\\cdot m\\cdot\\beta^{e-t}$$ 该表示称为实数的浮点数表示。\n",
    "* $s$ 为符号位，整数 $m=a_{1}a_{2}...a_{t}$ 是一个 $t$ 位的整数，称为尾数(mantissa)。显然 $0\\le m\\le\\beta^{t}-1$ 。\n",
    "* 整数 $e$ 称为指数(exponent),满足 $L\\le e\\le U$ 。一般选取 $L<0$ 为一个负整数，$U>0$ 为一个正整数。\n",
    "* 对于一个占用N位的实数而言，计算机中存储时会让符号位占一位， 有效数字 $a_{i},i=1,...,t$ 占t位，指数 $e$ 则占据剩下的 $N-t-1$ 位。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 单精度：$t=23$ ,e占8位。双精度： $t=52$, e占11位。\n",
    "* 为了保证数字表示的唯一性，一般假设 $a_1\\ne 0$ ，否则我们可以向右移动小数点一位并减少e一个单位即可。经过这样约定的浮点数表示称为正常化 (normalized) 的浮点数表达。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 例如 在没有正常化的以10为底的浮点数 $\\mathbb{F}(10,4,-1,4)$ 系统中，实数1可以有下列四种表达， $$0.1000\\cdot10^{1},0.0100\\cdot10^{2},0.0010\\cdot10^{3},0.0001\\cdot10^{4}$$ 但是经过正常化后，只有第一个是符合要求的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 容易发现，一个正常化表达的浮点数系统 $\\mathbb{F}(\\beta,t,L,U)$ 中的所有可表达的实数的绝对值一定介于 $x_{min}$ 和 $x_{max}$ 之间: $$x_{\\min}\\equiv\\beta^{L-1}\\leq|x|\\leq\\beta^{U}\\left(1-\\beta^{-t}\\right)\\equiv x_{\\max}$$\n",
    "* 为了能够表达更多 (特别是绝对值更小) 的数，一般会将上述正常化后的浮点数系统与 $e=L$ 时的放弃要求 $a_{1}\\ne0$ 的系统 (由于 $e=L$ ，因此这不会破坏数表示的唯一性) 合并。 这可以产生在 $(-\\beta^{L-1},\\beta^{L-1})$ 中的实数。这使得最小绝对值下降为 $\\beta^{L-t}$ 。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 浮点数的分布不是连续的。事实上也不是均匀的。\n",
    "* 假定有两个非零的浮点数 $x,y\\in\\mathbb{F}$ ，两者最近的距离一定介于 $\\beta^{-1}\\epsilon_{M}|x| 和\\epsilon_{M}|x|$ 之间。其中的 $\\epsilon_{M}=\\beta^{1-t}$ 就是前面引入的机器精度(machineepsilon)，它实际上是最小的满足 $1+\\epsilon_{M}>1$ 的正实数。对于二进制来说， $\\epsilon_{M}\\sim10^{-7}$ ，如果取 $t = 23$ ; $\\epsilon_{M}\\sim10^{-16}$ ，如果取 $t = 52$。\n",
    "* 如果考察相邻两个浮点数的相对误差，则是只依赖于该数的尾数的函数，因此实际上是周期的 $$\\frac{\\Delta x}{x}=\\frac{(-)^{s}\\beta^{e-t}}{(-)^{s}m(x)\\beta^{e-t}}=\\frac{1}{m(x)}$$ 由于 $\\beta^{t-1}\\le m(x)<\\beta^{t}-1$ ，因此上述的相对误差会在 $[1/(\\beta^{t}-1),\\beta^{1-t}=\\epsilon_{M}]$ 之间震荡。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 对于那些不在系统F中的实数,最常见的操作称为舍入。最简单的舍入方法就是利用大家熟悉的“四舍五入”原则。\n",
    "* 任何实数都可以写出浮点数的形式，只是尾数可以有无穷多位。考察某个实数的尾数的下一位，$a_{t+1}$ 并且进行四舍五入的操作:如果它比 $\\beta/2$ 要小，就直接舍掉;如果它大或等于$\\beta/2$ ，就将前一位加1。\n",
    "* 当然，绝对值过大的实数仍然无法表达，这时候计算机会产生一个溢出 (overflow), 一般会停止运行。如果某个实数绝对值过小，$|x|<x_{min}$ ，这时候产生的一般称为下溢(underflow),此时往往系统会将其舍入为 0。\n",
    "* 舍入造成的误差可以进行量化的估计。对于任意的 $x\\in R$ ，且满足 $x_{min}\\le|x|\\le x_{max}$ ， 我们一定有，$$fl(x)=x(1+\\delta),|\\delta|\\leq\\frac{1}{2}\\beta^{1-t}=\\frac{1}{2}\\epsilon_{M}$$ 因此又称 $\\epsilon_{M}/2$ 为舍入误差单位 (roundoff unit)。浮点数的表示以及运算都是有误差的。\n",
    "* 一般来说，由于舍入问题的存在，计算机中的基本运算比如，加减法、乘法等等，并不满足原先数学中的结合律、分配率等基本规律。\n",
    "* 舍入方法的实现应当尽量确保在一次基本运算后造成的舍入误差仅仅在一两个机器精度的范围之内。\n",
    "* 由于计算机在复杂的算法中往往需要进行N多次的计算，因此我们必须考虑这种误差的传递和累计效应。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 误差及算法的稳定性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 算法：在计算数学中，从 n个已知的数据 $x\\in\\mathbb{R}^{n}$ 出发， 最终获得最终m个结果 $y\\in\\mathbb{R}^{m}$ 的一系列有限多次的操作之集合就构成了一个算法。\n",
    "* 一个好的算法：\n",
    "  *  首先必须是准确的;也就是说，它可以给出问题的足够精确的近似解。\n",
    "  *  在计算资源方面比较快捷和有效的。当然正确性仍然是首要考虑。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 每次计算机的操作往往都伴随着舍入误差，我们就需要分析这个误差是如何随着算法的发展而传递的。\n",
    "* 假定我们需要计算三个实数a,b,c的和，即a+b+c，有两个算法来进行这个计算，即(a+b)+c和a+(b+c)。这两种算法对应的误差可以分析如下\n",
    "  * 对(a+b)+c而言，我们有 $$a\\oplus b=(a+b)\\left(1+\\varepsilon_{1}\\right),\\\\(a\\oplus b)\\oplus c =\\left[(a+b)\\left(1+\\varepsilon_{1}\\right)+c\\right]\\left(1+\\varepsilon_{2}\\right)$$ 忽略掉二阶的无穷小量得到这个算法的结果为，$$(a\\oplus b)\\oplus c=(a+b+c)\\left[1+\\frac{a+b}{a+b+c}\\varepsilon_{1}+\\varepsilon_{2}\\right]$$ 另外一种算法的误差估计就是将 a 与 c 互换，即， $$(b\\oplus c)\\oplus a=(a+b+c)\\left[1+\\frac{c+b}{a+b+c}\\varepsilon_{1}+\\varepsilon_{2}\\right]$$ 两种算法有一个部分是相同的，即 $\\varepsilon_{2}$ 的部分;但是另外一个部分的放大因子分别为 $(a+b)/(a+b+c)$ 和 $(b+c)/(a+b+c)$ 。注意，这两个因子可以相差很远!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 两个因子的比为 $$\\left|\\frac{a+b}{c+b}\\right|$$ 这意味着，如果某两个之和恰好特别小，比如两个数几乎正负相消 ( $a+b\\simeq0$ )，那么先进行这两个数的加法的计算是更好的。事实上另外一种加法所产生的误差比首先进行几乎相消的两个数的加法要大很多倍。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.4 python语言简介"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一些参考资料\n",
    "* https://www.w3school.com.cn/python/python_sets.asp\n",
    "* https://www.runoob.com/python3/python3-tutorial.html\n",
    "* Python编程：从入门到实践 人民邮电出版社 2016.7"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Python 的设计具有很强的可读性，相比其他语言经常使用英文关键字，其他语言的一些标点符号，它具有比其他语言更有特色语法结构。\n",
    "\n",
    "* Python 是一种解释型语言： 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。\n",
    "\n",
    "* Python 是交互式语言： 这意味着，您可以在一个 Python 提示符 >>> 后直接执行代码。\n",
    "\n",
    "* Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。\n",
    "\n",
    "* Python 是初学者的语言：Python 对初级程序员而言，是一种伟大的语言，它支持广泛的应用程序开发，从简单的文字处理到 WWW 浏览器再到游戏。\n",
    "\n",
    "* 推荐安装anaconda，IDE可以用pycharm或vs code。上机练习使用jupyter。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 试试交互式编程和脚本式编程模式\n",
    "* Python与其他语言最大的区别就是，\n",
    "Python 的代码块不使用大括号{} 来控制类，函数以及其他逻辑判断。\n",
    "python 最具特色的就是用缩进来写模块。\n",
    "缩进的空白数量是可变的，但是所有代码块语句必须包含相同的缩进空白数量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 变量的使用和输出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "* python 属于动态语言，会有专门的Python解释器，将代码翻译成机器码来运行。\n",
    "* 动态语言：变量类型运行时检查，程序运行时可以改变结构。\n",
    "* 静态语言：编译时检查变量类型\n",
    "* 使用print()函数来显示。(注意python3和python2用法不同。我们选用python3的语法。)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"hello world\")\n",
    "print(\"你好，世界。\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message = \"Hello world!\"\n",
    "print(message)\n",
    "message = \"Hello Python world!\"\n",
    "print(message)\n",
    "message = 0\n",
    "print(message)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 变量名只能包含字母、数字和下划线。可以以字母和下划线开头，但不能以数字开头。\n",
    "* 变量名不能包含空格\n",
    "* 不要将python关键字和函数名用作变量名\n",
    "* 变量的取名很重要！遵循良好的命名准则。\n",
    "* 注意一些字母和数字的显示，比如l和1，O和0\n",
    "* 避免变量拼写错误。。。(现代的编辑器会帮你检查)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "message = \"Hello world!\"\n",
    "print(mesage)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import keyword\n",
    "print(keyword.kwlist)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 练一练\n",
    "给变量赋值，并将其打印出来。多个变量打印？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 字符串变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 字符串：用单引号或双引号括起来的东东。（注意输入法！）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('hello \"world!\"',\n",
    "\"hello 'world!\", \n",
    "\"This's the first one.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 字符串的一些操作：\n",
    " * 大小写转换\n",
    " * 合并拼接字符串\n",
    " * 制表符和换行符\n",
    " * 字符串的内容转换为其他类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "name = \"chang sha\" \n",
    "print(name.title())\n",
    "name = \"Chang Sha\" \n",
    "print(name.upper()) \n",
    "print(name.lower())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 变量后面的点：python将所有的东西都视为对象。这里的name相当于字符串对象的实例，每个对象可以有自己的方法和属性。这里相当于调用了字符串的方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "first_name = \"san\"\n",
    "last_name = \"zhang\"\n",
    "full_name = first_name + \" \" + last_name\n",
    "print(full_name)\n",
    "print(\"Hello, \" + full_name.title() + \"!\")\n",
    "print(\"Python\")\n",
    "print(\"\\tPython\")\n",
    "print(\"Hello\\n\\tWorld!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 数字"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 整数，实数，复数，布尔数。\n",
    "* 数的初等运算及优先级。（多用括号）\n",
    "* 运算符：+, -, *, /, //, %, **\n",
    "* 比较运算符：==, >, <, !=, >=, <=\n",
    "* 位运算符：&, |, ^, ~, <<, >>\n",
    "* 逻辑运算符：and, or, not\n",
    "* 成员运算符：in, not in\n",
    "* 身份运算符: is, is not\n",
    "注意：is 用于判断两个变量引用对象是否为同一个， == 用于判断引用变量的值是否相等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 1 + 2 * 3**4 // 12\n",
    "b = 1 + 2 * 3**4 / 12\n",
    "c = (1+1j) * (2 + 3j)+1e2 - 3**(1/2)\n",
    "d = False\n",
    "print(a,type(a))\n",
    "print(b,type(b))\n",
    "print(c,type(c))\n",
    "print(d,type(d))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 10\n",
    "b = 20\n",
    "print(a and b)\n",
    "print(a or b)\n",
    "print(not True)\n",
    "print(not False)\n",
    "print(a is b)\n",
    "print(a is not b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 进制的表示：八进制，十六进制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(0b10,0o37,0xA0F)\n",
    "print(bin(2),oct(31),hex(2575))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 数字与字符串之间的转换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "age = 21\n",
    "print(\"Happy \" + str(age) + \"rd Birthday!\" )\n",
    "print(int(\"1\") + int(\"1\"))\n",
    "print(float(\"1\") + float(\"1\"))\n",
    "print(complex(\"1\") + complex(\"1\"))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 程序多写注释！\n",
    "* python的注释以#开头"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这是一段注释\n",
    "print(\"你看不到注释。\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import this"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 列表与元组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 列表由一系列按特定顺序排列的元素组成。\n",
    "* 用方括号[]来表示列表, 逗号来分隔元素，元素可以是其他任何对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [\"1\",1,1e10,1+2j,[2,2,2]]\n",
    "print(a)\n",
    "a = list(range(1,11,2))\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 访问列表元素\n",
    "    * 通过索引来访问列表中的元素，元素指标从0开始。\n",
    "    * 负的指标表示从后往前数。\n",
    "    * 通过指标可以将列表中的元素替换。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(a[0],a[1])\n",
    "a[0] =\"0\"\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 增减列表元素 \n",
    "    * 列表末尾添加元素:append()\n",
    "    * 列表中插入元素: insert()\n",
    "    * 列表中删除元素： del语句，pop()方法，remove方法()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a.append(\"b\")\n",
    "print(a)\n",
    "a.insert(2,\"c\")\n",
    "print(a)\n",
    "# 如果扔掉的元素不再需要，则用del，若需要取得，则用pop()\n",
    "del a[-1]\n",
    "print(a)\n",
    "a.pop(2)\n",
    "print(a)\n",
    "# 根据值来删除找到的第一元素。\n",
    "a.remove(\"0\")\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 列表排序\n",
    "    * 排序：sort()方法，sorted()函数,reverse()方法。 注意，排序列表的元素是可比较的。\n",
    "    * len()函数获取列表长度。\n",
    "    * 注意，列表访问容易发生索引错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [\"b\",\"c\", \"a\",\"d\"]\n",
    "a.sort()\n",
    "print(a)\n",
    "a.reverse()\n",
    "print(a)\n",
    "print(sorted(a))\n",
    "print(a)\n",
    "print(len(a))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 历遍列表\n",
    "   * 使用for循环历遍列表,方便对列表每个元素进行操作\n",
    "   * python以缩进来划分代码，注意分清语句的作用域\n",
    "   * 不要忘记for语句末尾的冒号\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in a:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 操作列表\n",
    "    * 列表解析:集成for循环来产生列表,range()函数很有用。\n",
    "    * 利用切片：来获取列表的一部分\n",
    "    * 复制列表: listA = listB 与 listA = listB[:]的区别"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [ i**2 for i in range(10)]\n",
    "print(a)\n",
    "print(a[1:2],a[:2],a[-3:-1])\n",
    "b = a\n",
    "print(b)\n",
    "a[0] = 1\n",
    "print(b)\n",
    "b = a[:]\n",
    "a[0] = 0\n",
    "print(b)\n",
    "b = [i**(1/2) for i in a]\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 元组\n",
    "    * 元组使用小括号()定义。一个元素的元组，元素后面要加逗号。\n",
    "    * 不可变的迭代对象。一旦定义，无法更改其元素。\n",
    "    * 选取元素的操作类似于列表\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = (1,2,3,4)\n",
    "print(a)\n",
    "print(a[1:3])\n",
    "b = ( 4, 5, 6)\n",
    "print(a+b)\n",
    "a = tuple(range(10))\n",
    "print(a)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 字典"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 字典是另一种可变容器模型，且可存储任意类型对象。\n",
    "* 由放在花括号的键值对组成{key:vale,...}\n",
    "* key是唯一的，是不可变的，如字符串，数字。value可以是任意对象。\n",
    "* 使用 items()来获取迭代的键值对\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = {\"1\":0, 1:2, \"3\":list(range(10))}\n",
    "print(a[\"1\"],a[1])\n",
    "for key,val in a.items():\n",
    "    print(key,val)\n",
    "a[\"1\"] = 1\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 集合"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 集合（set）是一个无序的不重复元素序列。用set()或{}来创建，但{}不能用来创建空集合\n",
    "* 集合同样属于可迭代对象。有add,remove,discard等方法\n",
    "* 可以进行交集、差集、并集等运算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "thisset = {\"apple\", \"banana\", \"cherry\"}\n",
    "for x in thisset:\n",
    "  print(x)\n",
    "\n",
    "thisset.add(\"orange\")\n",
    "print(thisset)\n",
    "\n",
    "thisset = {\"apple\", \"banana\", \"cherry\"}\n",
    "thisset.remove(\"banana\")\n",
    "print(thisset)\n",
    "\n",
    "set1 = {\"a\", \"b\" , \"c\"}\n",
    "set2 = {1, 2, 3}\n",
    "set3 = set1.union(set2)\n",
    "print(set3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 常用语句"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 条件语句"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 通常需要用一些条件判断来控制程序的走向。\n",
    "* python中主要用if语句来实现，没有switch语句\n",
    "```\n",
    "if 判断条件1:\n",
    "    执行语句1……\n",
    "elif 判断条件2:\n",
    "    执行语句2……\n",
    "elif 判断条件3:\n",
    "    执行语句3……\n",
    "else:\n",
    "    执行语句4……\n",
    "```\n",
    "* 可以没有elif 和else部分。\n",
    "* 判断条件里经常使用前面介绍的各类运算，多练习熟悉。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "num = 9\n",
    "if num >= 0 and num <= 10:    # 判断值是否在0~10之间\n",
    "    print('hello')\n",
    "# 输出结果: hello\n",
    " \n",
    "num = 10\n",
    "if num < 0 or num > 10:    # 判断值是否在小于0或大于10\n",
    "    print('hello')\n",
    "else:\n",
    "    print('undefine')\n",
    "# 输出结果: undefine\n",
    " \n",
    "num = 8\n",
    "# 判断值是否在0~5或者10~15之间\n",
    "if (num >= 0 and num <= 5) or (num >= 10 and num <= 15):    \n",
    "    print('hello')\n",
    "else:\n",
    "    print('undefine')\n",
    "# 输出结果: undefine"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 循环语句"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* for语句是使用最广泛的循环语句\n",
    "* for语句的结构为\n",
    "```\n",
    "for iterating_var in sequence:\n",
    "   statements(s)\n",
    "```\n",
    "* sequence可以是任意的可迭代对象，如字符串，列表，元祖，字典等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for letter in 'Python':     # \n",
    "   print(\"当前字母: %s\" % letter)\n",
    " \n",
    "fruits = ['banana', 'apple',  'mango']\n",
    "for fruit in fruits:        # 列表\n",
    "   print ('当前水果: %s'% fruit)\n",
    " \n",
    "print (\"Good bye!\")\n",
    "\n",
    "fruits = ['banana', 'apple',  'mango']\n",
    "for index in range(len(fruits)): # 通过列表的指标循环\n",
    "   print ('当前水果 : %s' % fruits[index])\n",
    " \n",
    "print (\"Good bye!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]\n",
    "b = a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a[0][1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* while 语句, 如果条件满足则执行，否则不执行。\n",
    "```\n",
    "while 判断条件(condition)：\n",
    "    执行语句(statements)……\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "count = 0\n",
    "while (count < 9):\n",
    "   print( 'The count is:', count)\n",
    "   count = count + 1\n",
    " \n",
    "print(\"Good bye!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* countinue 和 break用来跳出循环\n",
    "* countinue 跳过后面的语句进入下一次循环\n",
    "* break跳出当前循环体。如果多重循环会进入到上层循环体中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for letter in 'Python':     # 第一个实例\n",
    "   if letter == 'h':\n",
    "      break\n",
    "   print ('当前字母 :', letter)\n",
    "  \n",
    "var = 10                    # 第二个实例\n",
    "while var > 0:              \n",
    "   print('当前变量值 :', var)\n",
    "   var = var -1\n",
    "   if var == 5:   # 当变量 var 等于 5 时退出循环\n",
    "      break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* pass 不做任何事情，一般用做占位语句。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for letter in 'Python':\n",
    "   if letter == 'h':\n",
    "      pass\n",
    "      print ('这是 pass 块')\n",
    "   print ('当前字母 :', letter)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 定义函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 关键字 def 来定义函数，后接函数名 + 括号加冒号，注意缩进。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def greet_user():  \n",
    "    \"\"\"显示简单的问候语\"\"\"\n",
    "    print(\"Hello!\")\n",
    "greet_user()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 传入参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def greet_user(username:str):  \n",
    "    \"\"\"显示简单的问候语\"\"\"\n",
    "    print(\"Hello \" + username + \"!\")\n",
    "greet_user(\"zhangsan\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* return 关键字后面跟函数返回值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add(a,b):\n",
    "    return a+b\n",
    "add(1,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 位置实参:按形参顺序对应传入实参"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def describe_pet(animal_type, pet_name) :\n",
    "    \"\"\"显示宠物的信息\"\"\"\n",
    "    print(\"\\nI have a \" + animal_type + \".\" + \" Its name is \" + pet_name + \".\")\n",
    "    # 另一种写法 print(f\"I have a {animal_type}. Its name is {pet_name}.\")\n",
    "describe_pet(\"dog\", \"wangwang\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 关键字实参:对形参指定实参"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_function(child3, child2, child1):\n",
    "  print(\"The youngest child is \" + child3)\n",
    "\n",
    "my_function(child1 = \"Phoebe\", child2 = \"Jennifer\", child3 = \"Rory\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 默认值参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_function(country = \"China\"):\n",
    "  print(\"I am from \" + country)\n",
    "\n",
    "my_function(\"India\")\n",
    "my_function()  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 事先不知道应该放入多少参数?\n",
    "* 使用 *args可以传入不定数目的参数, 此时函数会建立一个空的元组 args, 然后将所有实参放进该元组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_function(*kids):\n",
    "  print(\"The youngest child is \" + kids[2])\n",
    "\n",
    "my_function(\"Phoebe\", \"Jennifer\", \"Rory\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 任意数量的关键字参数?\n",
    "* 使用**args 传入指定关键字的参数，关键字与实 参组成键值对存入字典 args 中"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def show_scores(**courses): \n",
    "    \"\"\"选择课程\"\"\" \n",
    "    print(\"\\nYou choice courses as :\") \n",
    "    for course,score in courses: \n",
    "        print(\"\\n course \"+ course + \"'s score is \" + str(score)) \n",
    "show_scores(mathematics=90) \n",
    "show_scores(mathematics=90, physics=95, chemistry=92)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "• 总体来说函数参数的排列为：\n",
    "```\n",
    "def func(arg1, arg2, ..., keywords1=arg11, ..., *tuble, **dicts)\n",
    "```\n",
    "• 编写程序时，可以以各种方式混合使用各种实参。\n",
    "\n",
    "• 编写指南(只是建议）\n",
    "\n",
    "– 函数都以小写字母和下划线命名，名字应易懂。\n",
    "\n",
    "– 类名首字母大写单词不隔开，变量名全小写以下划线隔开，常量都用大写。尽量写全名\n",
    "\n",
    "– 函数后面跟着注释，说明函数的功能，更详细的可以说明参数的作用。\n",
    "\n",
    "– 函数和函数之间空两行\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "• 函数的优点是将一般性的方法分离，方便重复调用。通常将一定功能的函数放入同一个文件中，该文件被称为模块\n",
    "\n",
    "• 在其它程序调用模块中的函数时，使用imoprt 语句\n",
    "\n",
    "– import 模块名:导入整个模块\n",
    "\n",
    "– 调用该模块中的函数：模块名.函数名\n",
    "\n",
    "– 只导入特定函数: from module_name import func1, func2。此时调用只用函数名即可\n",
    "\n",
    "– 导入模块中所有的函数: from module_name import *。所有函数都被导入，可直接使用函数名调用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 输入输出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Python两种输出值的方式: 表达式语句和 <font color=red>print() </font> 函数。第三种方式是使用文件对象的 write() 方法，标准输出文件可以用 sys.stdout 引用。如果你希望输出的形式更加多样，可以使用 str.format() 函数来格式化输出值。如果你希望将输出的值转成字符串，可以使用 repr() 或 str() 函数来实现。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for x in range(1, 11):\n",
    "    print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*  input() 内置函数从标准输入读入一行文本，默认的标准输入是键盘。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "str = input(\"请输入：\");\n",
    "print (\"你输入的内容是: \", str)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 通过open()返回一个 file 对象,进行读写文件。open(filename, mode)\n",
    "  * filename：包含了你要访问的文件名称的字符串值\n",
    "  * mode：决定了打开文件的模式：只读，写入，追加等。这个参数是非强制的，默认文件访问模式为只读(r)。\n",
    "\n",
    "* 得到文件对象后，如f，可以用f.read()读入文件内容。调用 f.read(size), 这将读取一定数目的数据, 然后作为字符串或字节对象返回。size 是一个可选的数字类型的参数。 当 size 被忽略了或者为负, 那么该文件的所有内容都将被读取并且返回。\n",
    "* f.readline() 会从文件中读取单独的一行。换行符为 '\\n'。f.readline() 如果返回一个空字符串, 说明已经已经读取到最后一行。\n",
    "* f.readlines() 将返回该文件中包含的所有行。\n",
    "* f.write(string) 将 string 写入到文件中, 然后返回写入的字符数。\n",
    "* 当你处理完一个文件后, 调用 f.close() 来关闭文件并释放系统的资源，如果尝试再调用该文件，则会抛出异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 打开一个文件\n",
    "f = open(\"./foo.txt\", \"w\")\n",
    "\n",
    "num = f.write( \"Python 是一个非常好的语言。\\n是的，的确非常好!!\\n\" )\n",
    "print(num)\n",
    "# 关闭打开的文件\n",
    "f.close()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f = open(\"./foo.txt\",\"r\")\n",
    "print(f.read())\n",
    "f.close\n",
    "\n",
    "f = open(\"./foo.txt\",\"r\")\n",
    "print(f.readline())\n",
    "f.close\n",
    "\n",
    "f = open(\"./foo.txt\",\"r\")\n",
    "for line in f.readlines():\n",
    "    print(line)\n",
    "f.close\n",
    "\n",
    "with open(\"./foo.txt\",\"r\") as f:\n",
    "    for line in f.readlines():\n",
    "        print(line)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 类"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。\n",
    "* 方法：类中定义的函数。\n",
    "* 类变量：类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。\n",
    "* 数据成员：类变量或者实例变量用于处理类及其实例对象的相关的数据。\n",
    "* 方法重写：如果从父类继承的方法不能满足子类的需求，可以对其进行改写，这个过程叫方法的覆盖（override），也称为方法的重写。\n",
    "* 局部变量：定义在方法中的变量，只作用于当前实例的类。\n",
    "* 实例变量：在类的声明中，属性是用变量来表示的，这种变量就称为实例变量，实例变量就是一个用 self 修饰的变量。\n",
    "* 继承：即一个派生类（derived class）继承基类（base class）的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如，有这样一个设计：一个Dog类型的对象派生自Animal类，这是模拟\"是一个（is-a）\"关系（例图，Dog是一个Animal）。\n",
    "* 实例化：创建一个类的实例，类的具体对象。\n",
    "* 对象：通过类定义的数据结构实例。对象包括两个数据成员（类变量和实例变量）和方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyClass:\n",
    "    \"\"\"一个简单的类实例\"\"\"\n",
    "    i = 12345\n",
    "    def f(self):\n",
    "        return 'hello world'\n",
    " \n",
    "# 实例化类\n",
    "x = MyClass()\n",
    " \n",
    "# 访问类的属性和方法\n",
    "print(\"MyClass 类的属性 i 为：\", x.i)\n",
    "print(\"MyClass 类的方法 f 输出为：\", x.f())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 练习"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 将一个一维列表(从0到25)转换成二维列表（5，5）。\n",
    "2. 导入math包，将一些数学函数如cos,sin,exp等作用到一个一维及二维列表上。\n",
    "3. 实现矩阵与数及矩阵与矩阵之间的加、减、乘的函数（三个函数），并进行测试。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.5 numpy及matplotlib"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1.5.1 numpy https://numpy.org/doc/stable/user/index.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* numpy是当前广泛用于科学计算的python包，可以方便操作多维数组(可以对比一下用c或者fortran来写，或者原生的python的list实现)。\n",
    "* scipy 提供了更广泛的科学计算所需要的工具及函数。\n",
    "* sympy 则提供了在 python 环境下进行符号计算的软件包。\n",
    "* matplotlib则提供了丰富的数据可视化工具。\n",
    "* 常用的一些数值计算库LAPACK，FFTPACK，ODEPACK，MINPACK等"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 在python中安装第三方包，一般可以用pip和conda。\n",
    "    ``` shell\n",
    "    pip install package_name\n",
    "    conda install package_name\n",
    "    ```\n",
    "* 安装后，用import 导入包，import xxx as xx 来重命名。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 教程 https://numpy.org/doc/stable/user/absolute_beginners.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 快速创建数组\n",
    "  * 由python的一些对象直接创建,如list或元组,`numpy.array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0,like=None)`。\n",
    "  * `numpy.arange([start, ]stop, [step, ]dtype=None)`\n",
    "  * `numpy.linspace(start, stop, num=50, endpoint=True,retstep=False, dtype=None)`，缺省包含终值\n",
    "  * `numpy.diag(v, k=0),numpy.ones(shape, dtype=None, order=’C’)`\n",
    "  * `numpy.empty(shape, dtype=float, order=’C’),numpy.zeros(shape, dtype=float, order=’C’)`\n",
    "  * `numpy.fromfunction(function, shape, **kwargs)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def split_line(n=30):\n",
    "    print(n*\"=\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_of_split=10\n",
    "a = np.array([1.,2.,3.,4.])\n",
    "print(a,type(a))\n",
    "split_line()\n",
    "\n",
    "a = np.arange(1.1,2.4,0.2)\n",
    "print(a)\n",
    "split_line()\n",
    "\n",
    "a = np.linspace(1.1,2.4,7)\n",
    "print(a)\n",
    "split_line()\n",
    "\n",
    "a = np.diag([1.,2.,3.])\n",
    "b = np.diag([1.,2.,3.],1)\n",
    "print(a)\n",
    "print(b)\n",
    "split_line()\n",
    "\n",
    "a = np.zeros((4,))\n",
    "b = np.zeros((4,4)) \n",
    "print(a)\n",
    "print(b)\n",
    "split_line()\n",
    "\n",
    "a = np.fromfunction(lambda x:x**2,(4,))\n",
    "b = np.fromfunction(lambda i,j:(i**2+j**2)**0.5,(4,4))\n",
    "print(a)\n",
    "print(b)\n",
    "split_line()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 查看和改变数组的形状\n",
    "  * shape\n",
    "  * reshape\n",
    "  * flatten"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.arange(12)\n",
    "print(a.shape)\n",
    "split_line()\n",
    "\n",
    "a.shape=(3,4)\n",
    "print(a)\n",
    "a.shape=(4,3)\n",
    "print(a)\n",
    "a.shape=(6,-1)\n",
    "print(a)\n",
    "split_line()\n",
    "\n",
    "b = a.reshape((3,4))\n",
    "print(a)\n",
    "print(b)\n",
    "\n",
    "print(b.flatten())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 存取元素\n",
    "  * 数组元素的存取方法和 Python 的标准方法相同\n",
    "  * 和 Python 的列表序列不同，通过下标范围获取的新的数组是原始数组的一个视图.它与原始数组共享同一块数据空间\n",
    "  * 还可以使用整数序列和使用布尔数组来选对数组位置\n",
    "  * 一维数组指标示意图\n",
    "  ![一维数组指标示意图](./pic/sec1-indexing.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = a[:3]\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a[0,0] = -1\n",
    "a[0][0]\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a[0,0] = -1\n",
    "b = a[:3].copy()\n",
    "a[0,0] = 0\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a[[1,3,2]]\n",
    "print(a)\n",
    "\n",
    "b=np.array([[True,False],[True,False],[True,False],[True,False],[True,False],[True,False]])\n",
    "print(b)\n",
    "print(a[b])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a>5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.arange(12)\n",
    "print(a[a>4])\n",
    "print(a[(a>2) & (a<5)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 拼接和分割数组：concatenate ,split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.arange(3)\n",
    "b = np.arange(4)\n",
    "print(np.concatenate((a,b)))\n",
    "split_line()\n",
    "\n",
    "a = np.arange(2).reshape(1,2)\n",
    "b = np.arange(4).reshape(2,2)\n",
    "print(np.concatenate((a,b)))\n",
    "split_line()\n",
    "\n",
    "a = np.arange(16)\n",
    "print(np.split(a,4))\n",
    "split_line()\n",
    "\n",
    "a = np.arange(16).reshape(4,4)\n",
    "print(np.split(a,2))\n",
    "split_line()\n",
    "\n",
    "a = np.arange(16)\n",
    "print(np.split(a,[3,7]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 增加或冻结维度 np.newaxis, np.expand_dims, np.squeeze"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.arange(4)\n",
    "print(a.shape,a[:,np.newaxis].shape,a[np.newaxis,:].shape)\n",
    "\n",
    "print(np.expand_dims(a,0).shape,np.expand_dims(a,1).shape,np.expand_dims(a,(0,1)).shape,np.expand_dims(a,(1,2)).shape)\n",
    "\n",
    "c = np.expand_dims(a,(1,2))\n",
    "print(c.shape,np.squeeze(c).shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 数组的运算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = np.array([1, 2])\n",
    "ones = np.ones(2, dtype=int)\n",
    "data + ones"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(data - ones)\n",
    "print(data * data)\n",
    "print(data / data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array([1, 2, 3, 4])\n",
    "print(a.sum())\n",
    "\n",
    "b = np.array([[1, 1], [2, 2]])\n",
    "print(b.sum(axis=0))\n",
    "\n",
    "print(b.sum(axis=1))\n",
    "\n",
    "print(a * 0.3)\n",
    "\n",
    "#print(a * b) 注意维度\n",
    "print(a.reshape(2,2)*b)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 查看函数用法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "help(np.max)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* ufunc\n",
    "    * ufunc 是一种能对数组每个元素进行操作的函数. 内置函数大多都是在 C 语言级别实现的，运算速度非常快\n",
    "    * 各类常见的数学函数:sum，sin，exp，average，\n",
    "    * 复杂的操作可能会产生大量的中间结果而降低程序的运行效率"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.arange(12)\n",
    "print(np.sin(a * 2 * np.pi /12))\n",
    "split_line()\n",
    "print(np.cos(a * 2 * np.pi /12))\n",
    "\n",
    "split_line()\n",
    "print(np.average(a))\n",
    "print(np.average(a.reshape(3,4),0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* ufunc运算规则\n",
    "    1. 让所有输入数组都向其中 shape 最长的数组 看齐，shape 中不足的部分都通过在前面加 1 补 齐\n",
    "    2. 输出数组的 shape 是输入数组 shape 的各个 轴上的最大值\n",
    "    3. 如果输入数组的某个轴和输出数组的对应轴的 长度相同或者其长度为 1 时，这个数组能够用来 计算，否则出错\n",
    "    4. 当输入数组的某个轴的长度为 1 时，沿着此轴 运算时都用此轴上的第一组值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.arange(0, 60, 10).reshape(-1, 1)\n",
    "b = np.arange(0, 5)\n",
    "c=a+b\n",
    "print(a,\"\\n\",b,\"\\n\",c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 自定义ufunc：\n",
    "```python\n",
    "  class numpy.vectorize(pyfunc, otypes=None,\n",
    "doc=None, excluded=None, cache=False, signature=None)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def myfunc(a, b) :\n",
    "    \"Return a-b if a>b, otherwise return a+b\" \n",
    "    if a > b:\n",
    "        return a - b \n",
    "    else:\n",
    "        return a + b\n",
    "vfunc = np.vectorize(myfunc)\n",
    "vfunc([1 ,2 ,3 ,4] ,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 文件读写\n",
    "  * 最简单的方式，用`np.save()`保存文件，用`np.load()`读取文件。这样会存有数据的维度及类型信息。\n",
    "  * 读写取二进制文件,可以用`numpy.fromfile`，ndarray可以使用`tofile()`方法保存为二进制文件，\n",
    "  ```python\n",
    "  numpy.fromfile(file, dtype=float, count=- 1, sep='', offset=0, *, like=None)\n",
    "  ndarray.tofile(fid, sep='', format='%s') # 注意ndarray才有tofile\n",
    "  ```\n",
    "  读入后是一个一维的数组。\n",
    "  * 读取文本文件，可以用`np.loadtxt()`。\n",
    "  ```python\n",
    "  numpy.loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0, encoding='bytes', max_rows=None, *, quotechar=None, like=None)\n",
    "  ```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 15.2 scipy 更丰富的科学计算库"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "https://scipy.github.io/devdocs/tutorial/index.html\n",
    "* 特殊函数 scipy.special\n",
    "  * 贝塞尔函数\n",
    "  $$x^2 \\frac{d^2 y}{d x^2}+x \\frac{d y}{d x}+\\left(x^2-\\alpha^2\\right) y=0$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy import special\n",
    "import numpy as np\n",
    "def drumhead_height(n, k, distance, angle, t):\n",
    "   kth_zero = special.jn_zeros(n, k)[-1]\n",
    "   return np.cos(t) * np.cos(n*angle) * special.jn(n, distance*kth_zero)\n",
    "theta = np.r_[0:2*np.pi:50j]\n",
    "radius = np.r_[0:1:50j]\n",
    "x = np.array([r * np.cos(theta) for r in radius])\n",
    "y = np.array([r * np.sin(theta) for r in radius])\n",
    "z = np.array([drumhead_height(1, 1, r, theta, 0.5) for r in radius])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "fig = plt.figure()\n",
    "ax = fig.add_axes(rect=(0, 0.05, 0.95, 0.95), projection='3d')\n",
    "ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap='RdBu_r', vmin=-0.5, vmax=0.5)\n",
    "ax.set_xlabel('X')\n",
    "ax.set_ylabel('Y')\n",
    "ax.set_xticks(np.arange(-1, 1.1, 0.5))\n",
    "ax.set_yticks(np.arange(-1, 1.1, 0.5))\n",
    "ax.set_zlabel('Z')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 积分 scipy.integrate\n",
    "  * 计算积分\n",
    "  $$I=\\int_0^{4.5} J_{2.5}(x) d x$$\n",
    "  * 解析结果\n",
    "  $$\\begin{aligned}&I=\\sqrt{\\frac{2}{\\pi}}\\left(\\frac{18}{27} \\sqrt{2} \\cos (4.5)-\\frac{4}{27} \\sqrt{2} \\sin (4.5)+\\sqrt{2 \\pi} \\operatorname{Si}\\left(\\frac{3}{\\sqrt{\\pi}}\\right)\\right)\\\\&\\operatorname{Si}(x)=\\int_0^x \\sin \\left(\\frac{\\pi}{2} t^2\\right) d t\\end{aligned}$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import scipy.integrate as integrate\n",
    "import scipy.special as special\n",
    "result = integrate.quad(lambda x: special.jv(2.5,x), 0, 4.5)\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from numpy import sqrt, sin, cos, pi\n",
    "I = sqrt(2/pi)*(18.0/27*sqrt(2)*cos(4.5) - 4.0/27*sqrt(2)*sin(4.5) +\n",
    "                sqrt(2*pi) * special.fresnel(3/sqrt(pi))[0])\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 函数极值及优化 scipy.optimize\n",
    "  * $$f(\\mathbf{x})=\\sum_{i=1}^{N-1} 100\\left(x_{i+1}-x_i^2\\right)^2+\\left(1-x_i\\right)^2$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy.optimize import minimize\n",
    "def rosen(x):\n",
    "    \"\"\"The Rosenbrock function\"\"\"\n",
    "    return sum(100.0*(x[1:]-x[:-1]**2.0)**2.0 + (1-x[:-1])**2.0)\n",
    "\n",
    "x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])\n",
    "res = minimize(rosen, x0, method='nelder-mead',\n",
    "               options={'xatol': 1e-8, 'disp': True})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 函数插值 scipy.interpolate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.interpolate import CubicSpline\n",
    "x = np.linspace(0, 10, num=11)\n",
    "y = np.cos(-x**2 / 9.)\n",
    "spl = CubicSpline(x, y)\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "fig, ax = plt.subplots(4, 1, figsize=(5, 7))\n",
    "xnew = np.linspace(0, 10, num=1001)\n",
    "ax[0].plot(xnew, spl(xnew))\n",
    "ax[0].plot(x, y, 'o', label='data')\n",
    "ax[1].plot(xnew, spl(xnew, nu=1), '--', label='1st derivative')\n",
    "ax[2].plot(xnew, spl(xnew, nu=2), '--', label='2nd derivative')\n",
    "ax[3].plot(xnew, spl(xnew, nu=3), '--', label='3rd derivative')\n",
    "for j in range(4):\n",
    "    ax[j].legend(loc='best')\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 快速傅立叶变换 scipy.fft"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from scipy.fft import fft, fftfreq\n",
    "import numpy as np\n",
    "# Number of sample points\n",
    "N = 600\n",
    "# sample spacing\n",
    "T = 1.0 / 800.0\n",
    "x = np.linspace(0.0, N*T, N, endpoint=False)\n",
    "y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)\n",
    "yf = fft(y)\n",
    "xf = fftfreq(N, T)[:N//2]\n",
    "import matplotlib.pyplot as plt\n",
    "plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]))\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 线性代数 scipy.linalg （numpy 也有大量的函数）\n",
    "  * 矩阵求逆\n",
    "  $$\\begin{gathered}\\mathbf{A}=\\left[\\begin{array}{lll}1 & 3 & 5 \\\\2 & 5 & 1 \\\\2 & 3 & 8\\end{array}\\right], \\\\\\mathbf{A}^{-1}=\\frac{1}{25}\\left[\\begin{array}{ccc}-37 & 9 & 22 \\\\14 & 2 & -9 \\\\4 & -3 & 1\\end{array}\\right]=\\left[\\begin{array}{ccc}-1.48 & 0.36 & 0.88 \\\\0.56 & 0.08 & -0.36 \\\\0.16 & -0.12 & 0.04\\end{array}\\right] .\\end{gathered}$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy import linalg\n",
    "A = np.array([[1,3,5],[2,5,1],[2,3,8]])\n",
    "linalg.inv(A)\n",
    "A.dot(linalg.inv(A)) #double check"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1.5.3 matplotlib作图"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 画一维函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.arange(0,4*np.pi,0.1)\n",
    "y = np.sin(x)\n",
    "z = np.cos(x)\n",
    "plt.plot(x,y,x,z)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 画一维的数据点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([0.1, 0.5, 0.9, 1.2, 1.3])\n",
    "y = np.array([1.2, 1.4, 1.7, 1.9, 2.4])\n",
    "plt.plot(x,y,\"*\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 带有误差的数据点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([0.1, 0.5, 0.9, 1.2, 1.3])\n",
    "y = np.array([1.2, 1.4, 1.7, 1.9, 2.4])\n",
    "yerr = np.array([0.2, 0.2, 0.3, 0.3, 0.5])\n",
    "plt.errorbar(x,y,yerr,fmt=\"o\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 柱形图及饼图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([\"sec1\", \"sec2\", \"sec3\", \"sec4\"])\n",
    "y = np.array([12, 22, 6, 18])\n",
    "\n",
    "plt.bar(x,y)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "y = np.array([35, 25, 25, 15])\n",
    "\n",
    "plt.pie(y,\n",
    "        labels=['A','B','C','D'], # 设置饼图标签\n",
    "        colors=[\"#d5695d\", \"#5d8ca8\", \"#65a479\", \"#a564c9\"], # 设置饼图颜色\n",
    "        explode=(0, 0.2, 0, 0), # 第二部分突出显示，值越大，距离中心越远\n",
    "        autopct='%.2f%%', # 格式化输出百分比\n",
    "       )\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 子图绘图及标签"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ax1=plt.subplot(1, 2, 1)\n",
    "plt.title(\"sin and cos\")\n",
    "x = np.arange(0,4*np.pi,0.1)\n",
    "y = np.sin(x)\n",
    "z = np.cos(x)\n",
    "#ax1.set_xlabel=\"x\"\n",
    "#ax1.set_ylabel=\"f(x)\"\n",
    "plt.grid()\n",
    "plt.xlim((0,5*np.pi))\n",
    "plt.ylim((-1.2,1.5))\n",
    "plt.plot(x,y,\"b-\",label=\"sin\")\n",
    "plt.plot(x,z,\"r-.\",label=\"cos\")\n",
    "plt.xlabel(\"x\")\n",
    "plt.ylabel(\"f(x)\")\n",
    "plt.legend()\n",
    "\n",
    "\n",
    "ax2=plt.subplot(1, 2, 2)\n",
    "plt.title(\"data with error\")\n",
    "x = np.array([0.1, 0.5, 0.9, 1.2, 1.3])\n",
    "y = np.array([1.2, 1.4, 1.7, 1.9, 2.4])\n",
    "yerr = np.array([0.2, 0.2, 0.3, 0.3, 0.5])\n",
    "plt.xlim((0,1.7))\n",
    "plt.grid()\n",
    "plt.errorbar(x,y,yerr,fmt=\"ks\",ecolor=\"r\",label=\"data1\")\n",
    "plt.xlabel(\"r (cm)\")\n",
    "plt.ylabel(\"length (cm)\")\n",
    "plt.legend()\n",
    "\n",
    "plt.subplots_adjust(wspace=0.4)\n",
    "plt.suptitle(\"multi figures\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* 电磁场"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.figure()\n",
    "\n",
    "LX, LY=2,2\n",
    "\n",
    "gridwidth=0.2\n",
    "X, Y= np.meshgrid(np.arange(-LX, LX, gridwidth), np.arange(-LY, LY,gridwidth))\n",
    "\n",
    "R = np.sqrt(X**2+Y**2)\n",
    "\n",
    "X1,Y1=1.1,0\n",
    "Q1=1\n",
    "R1=np.sqrt((X-X1)**2+(Y-Y1)**2)\n",
    "plt.plot(X1,Y1,'o',color='blue')\n",
    "\n",
    "X2,Y2=-1.1,0\n",
    "Q2=-1\n",
    "R2=np.sqrt((X-X2)**2+(Y-Y2)**2)\n",
    "plt.plot(X2,Y2,'o',color='blue')\n",
    "##\n",
    "\n",
    "U = Q1*(X-X1)/(R1**2)+Q2*(X-X2)/(R2**2)\n",
    "V = Q1*(Y-Y1)/(R1**2)+Q2*(Y-Y2)/(R2**2)\n",
    "\n",
    "plt.quiver(X,Y,U,V,color='red',angles='xy',scale_units='xy', scale=6.5)\n",
    "\n",
    "\n",
    "plt.xlim([-LX,LX])\n",
    "plt.ylim([-LY,LY])\n",
    "\n",
    "plt.grid()\n",
    "plt.draw()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.9.12 ('base')",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "36b5677e7909a0b3d34004c01c225c0a9ffb16d3aacb819783bafe2786ef65fe"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
